﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Runtime.CompilerServices;
using System.Web;
using DAL;
using System.Linq;
using System.Web.Caching;
using System.Text.RegularExpressions;

namespace CustomProviders
{
    /// <summary>
    /// Summary description for SqlSiteMapProvider
    /// </summary>
    public class DropDownMenuProvider : StaticSiteMapProvider
    {
	    private const string _errmsg2 = "Duplicate node ID";
	    SiteMapNode _root;
        private readonly object _lock = new object();
        public DropDownMenuProvider()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private SiteMapNode SetParent(Category[] categories, int i)
        {
            if (i >= categories.Count())
                return null;
            SiteMapNode node = null;
            string url = null;
            if (i == 0)
            {
                // TODO We need to avoid hardcoded strings
                if (categories[i].Url == null)
                    url = string.Format("~/Product.aspx?id={0}", categories[i].CategoryId);
                else
                {
                    url = (categories[i].Url.UrlValue.Contains("{0}")) ? string.Format(categories[i].Url.UrlValue, categories[i].CategoryId) : categories[i].Url.UrlValue;
                }
                node = new SiteMapNode(this, categories[i].CategoryId.ToString(), url, categories[i].Title);
            }
            else
            {
                // TODO We need to avoid hardcoded strings
                if (categories[i].Url == null)
                    url = string.Format("~/Category.aspx?id={0}", categories[i].CategoryId);
                else
                {
                    url = (categories[i].Url.UrlValue.Contains("{0}")) ? string.Format(categories[i].Url.UrlValue, categories[i].CategoryId) : categories[i].Url.UrlValue;
                }
                node = new SiteMapNode(this, categories[i].CategoryId.ToString(), url, categories[i].Title);
            }
            node.ParentNode = SetParent(categories, ++i);
            return node;
        }
        public override SiteMapNode FindSiteMapNode(string rawUrl)
        {
            Match m = Regex.Match(rawUrl, "&page=\\d*");
            if (m.Success)
                rawUrl = rawUrl.Replace(m.Value, "");
            m = Regex.Match(rawUrl, "&bpage=\\d*");
            if (m.Success)
                rawUrl = rawUrl.Replace(m.Value, "");
            return base.FindSiteMapNode(rawUrl);
        }
        public override SiteMapNode FindSiteMapNode(HttpContext context)
        {
            string hnd = context.CurrentHandler.ToString();
            // TODO We need to avoid hardcoded strings
            if (hnd.ToUpper() == "ASP.PRODUCT_ASPX")
            {
                int? catId = Convert.ToInt32(context.Request.QueryString["id"]);
                if (catId == null)
                    return null;
                using (EShopDBDataContext db = new EShopDBDataContext())
                {
                    Category[] categories = null;
                    var siteMapPath = db.GetProductSiteMapPath(catId);
                    categories = siteMapPath.ToArray();
                    if (categories == null)
                        return null;
                    SiteMapNode currentNode = null;
                    currentNode = SetParent(categories, 0);
                    return currentNode;
                }
            }
            return base.FindSiteMapNode(context);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public override SiteMapNode BuildSiteMap()
        {
            lock (_lock)
            {
                
                // Return immediately if this method has been called before
                if (_root != null)
                    return _root;

                // Create a dictionary for temporary node storage and lookup
                Dictionary<int, SiteMapNode> nodes = new Dictionary<int, SiteMapNode>(16);

                using (
                    EShopDBDataContext db =
                        new EShopDBDataContext())
                {
                    // Extract all categories from DB
                    var allCategories = from c in db.Categories
                                        orderby c.CategoryId 
                                        select c;

                    var com = db.GetCommand(allCategories);
                    
                   
                    foreach (Category category in allCategories)
                    {
                        if (category.Parent == null)
                            _root = CreateNode(category, nodes);
                        else
                            CreateNode(category, nodes);
                    }
                    // Return the root SiteMapNode
                   
                    return _root;
                }
            }
        }



        public string[] GetRolesListIfAnyExist(Category category)
        {
            if (category.Roles != null)
            {
                string rolenames = category.Roles.Trim();
                if (!String.IsNullOrEmpty(rolenames))
                {
                    string[] rolelist = rolenames.Split(new char[] { ',', ';' }, 512);
                    return rolelist;
                }
            }
            return null;
        }
        private SiteMapNode CreateNode(Category category, Dictionary<int, SiteMapNode> nodes)
        {
            
            SiteMapNode parentnode = null;
            string url = string.Format("setCategory({0}, '{1}')", category.CategoryId, category.Title);
            SiteMapNode node = new SiteMapNode(this, category.CategoryId.ToString(), url, category.Title, "");
            node.Roles = GetRolesListIfAnyExist(category);
            // if it is root node (it must have no parent)
            if (category.Parent == null)
            {
                //  Add "*" to the roles list if no roles are specified
                if (node.Roles == null)
                    node.Roles = new string[] { "*" };
            }
            else
            {
                parentnode = nodes[Convert.ToInt32(category.Parent)];
                if (node.Roles == null)
                    node.Roles = parentnode.Roles;
            }
            // Record the root node in the dictionary
            if (nodes.ContainsKey(category.CategoryId))
                throw new ConfigurationErrorsException(_errmsg2); // ConfigurationException pre-Beta 2
            nodes.Add(category.CategoryId, node);
            // Add the node to the site map
            AddNode(node, parentnode);
            return node;
        }
        
        public void AddNodeToSiteMap(SiteMapNode node, SiteMapNode parentNode)
        {
            AddNode(node, parentNode);
        }
        protected override SiteMapNode GetRootNodeCore()
        {
            BuildSiteMap();
            return _root;
        }

        public void RemoveNodeFromSiteMap(SiteMapNode node)
        {
            RemoveNode(node);   
        }

        public void RebuildSiteMap()
        {
            this.Clear();
            _root = null;
        }
    }
}
